using System;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Diagnostics;
using System.Xml.Serialization;
using System.Xml;
using System.Runtime.InteropServices;
using System.Web.UI.HtmlControls;
using System.Collections;
using System.Text;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;

namespace SearchExtension.WebParts
{
    public enum PropertyRestrictionControlToUse
    {
        Dropdownlist = 0
    }

    public enum PropertyRestrictionDependentOnType
    {
        ParentFolder = 0
    }

    [ToolboxItemAttribute(false)]
    public class SearchExtensionWebPart : Microsoft.SharePoint.WebPartPages.WebPart, ICallbackEventHandler
    {
        private string configXml = string.Empty;
        private bool extensionDisabled = false;

        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public string ConfigXml
        {
            get
            {
                return configXml;
            }
            set
            {
                configXml = value;
            }
        }
        [Personalizable(PersonalizationScope.Shared)]
        [WebBrowsable(true)]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public bool ExtensionDisabled
        {
            get
            {
                return extensionDisabled;
            }
            set
            {
                extensionDisabled = value;
            }
        }


        public SearchExtensionWebPart()
        {
        }

        protected override void Render(HtmlTextWriter writer)
        {
            base.Render(writer);
        }

        protected override void OnPreRender(EventArgs e)
        {
            if (extensionDisabled) // DISABLED - do nothing
                return;

            try { RegisterScripts(); }
            catch (Exception exc)
            {
                try
                {
                    if (!EventLog.SourceExists("SearchExtension"))
                        EventLog.CreateEventSource("SearchExtension", "Application");
                    System.Diagnostics.EventLog.WriteEntry("SearchExtension", exc.Message + "\r\n\r\n" + exc.StackTrace);
                }
                catch { }
            }

            base.OnPreRender(e);
        }

        private void RegisterScripts()
        {
            String cbReference = Page.ClientScript.GetCallbackEventReference(this, "arg", "sewp_ReceiveServerData", "context");
            String callbackScript = callbackScript = "function sewp_CallServer(arg, context)" + "{ " + cbReference + ";}";
            Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "sewp_CallServer", callbackScript, true);

            string jsCallback = @"
//function sewp_MakeTheServerCall()
//{
//    sewp_CallServer('GetItemsFromList,');
//}

function sewp_ReceiveServerData(retValue)
{  
    eval(retValue);
}
";
            Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "jsCallback", jsCallback, true);


            //TESTING - SAMPLE CONFIG XML
            /*            if (string.IsNullOrEmpty(configXml))
                        {
                            configXml = @"
            <Configuration>
                <CustomPropertyRestrictionControls>
                    <ControlMapping OptionText="Category" ControlToUse="Dropdownlist" SourceList="Categories" SourceListParentWeb="TStester" ItemDisplayTextColumn="Title" ItemValueColumn="Title" ChildrenOptionText="Sub Category" DependentOnOptionText="" DependentOnType="" DuplicateAddedAlert="This property can not be selected more than once!" ExpandedWidth="Auto" /> 
                    <ControlMapping OptionText="Sub Category" ControlToUse="Dropdownlist" SourceList="Categories" SourceListParentWeb="TStester" ItemDisplayTextColumn="Title" ItemValueColumn="Title" ChildrenOptionText="" DependentOnOptionText="Category" DependentOnType="ParentFolder" DuplicateAddedAlert="This property can not be selected more than once!" ExpandedWidth="Auto" /> 
                    <ControlMapping OptionText="Query Status (Superceded)" ControlToUse="Dropdownlist">
                        <Option text="Yes" value="1" />
                        <Option text="No" value="0" />
                    </ControlMapping>
                    <ControlMapping OptionText="Query Status (Published Shared)" ControlToUse="Dropdownlist">
                        <Option text="Yes" value="1" />
                        <Option text="No" value="0" />
                    </ControlMapping>
                    <ControlMapping OptionText="Query Status (Sanitised)" ControlToUse="Dropdownlist">
                        <Option text="Yes" value="1" />
                        <Option text="No" value="0" />
                    </ControlMapping>
                    <ControlMapping OptionText="Query Status (Published)" ControlToUse="Dropdownlist">
                        <Option text="Yes" value="Published" />
                    </ControlMapping>
                </CustomPropertyRestrictionControls>
                <SecurityTrimmings>
                    <SecurityTrim OptionText="Query Status (Superceded)" Groups="TSApprovers,TSAdministrators,TSApplicationAdministrators,TSSharedInformationApprovers" TeamSiteUrl="/TStester" />
                    <SecurityTrim OptionText="Query Status (Published Shared)" Groups="TSApprovers,TSAdministrators,TSApplicationAdministrators,TSSharedInformationApprovers" TeamSiteUrl="/TStester" />
                    <SecurityTrim OptionText="Query Status (Sanitised)" Groups="TSApprovers,TSAdministrators,TSApplicationAdministrators,TSSharedInformationApprovers" TeamSiteUrl="/TStester" />
                </SecurityTrimmings>
            </Configuration>
            ";
                        }
                        */

            string js = @"var _sewp_controlMappings = new Array();
            ";


            // Evaluate the configuration and pass it to the client side in a js global variable
            if (configXml.Length < 1)
                return;

            this.Controls.Clear();
            XmlDocument xmlConfig = new XmlDocument();
            try
            {
                xmlConfig.LoadXml(configXml);
            }
            catch (Exception exc)
            {
                HtmlGenericControl err = new HtmlGenericControl("span");
                err.Attributes.Add("class", "ms-error");
                err.InnerText = exc.Message;
                this.Controls.Add(err);
                return;
            }


            // Custom property restrictions
            XmlNode controlMappings = xmlConfig.SelectSingleNode("/Configuration/CustomPropertyRestrictionControls");
            foreach (XmlNode controlMapping in controlMappings)
            {
                js += @"var sewp_controlMappings_entry = new Array();
                            sewp_controlMappings_entry['OptionText'] = '" + (controlMapping.Attributes["OptionText"] != null ? SPEncode.ScriptEncode(controlMapping.Attributes["OptionText"].Value) : string.Empty) + @"';
                            sewp_controlMappings_entry['ControlToUse'] = '" + (controlMapping.Attributes["ControlToUse"] != null ? SPEncode.ScriptEncode(controlMapping.Attributes["ControlToUse"].Value) : string.Empty) + @"';
                            sewp_controlMappings_entry['SourceList'] = '" + (controlMapping.Attributes["SourceList"] != null ? SPEncode.ScriptEncode(controlMapping.Attributes["SourceList"].Value) : string.Empty) + @"';
                            sewp_controlMappings_entry['SourceListParentWeb'] = '" + (controlMapping.Attributes["SourceListParentWeb"] != null ? SPEncode.ScriptEncode(controlMapping.Attributes["SourceListParentWeb"].Value) : string.Empty) + @"';
                            sewp_controlMappings_entry['ChildrenOptionText'] = '" + (controlMapping.Attributes["ChildrenOptionText"] != null ? SPEncode.ScriptEncode(controlMapping.Attributes["ChildrenOptionText"].Value) : string.Empty) + @"';
                            sewp_controlMappings_entry['DependentOnOptionText'] = '" + (controlMapping.Attributes["DependentOnOptionText"] != null ? SPEncode.ScriptEncode(controlMapping.Attributes["DependentOnOptionText"].Value) : string.Empty) + @"';
                            sewp_controlMappings_entry['DependentOnType'] = '" + (controlMapping.Attributes["DependentOnType"] != null ? SPEncode.ScriptEncode(controlMapping.Attributes["DependentOnType"].Value) : string.Empty) + @"';
                            sewp_controlMappings_entry['ItemDisplayTextColumn'] = '" + (controlMapping.Attributes["ItemDisplayTextColumn"] != null ? SPEncode.ScriptEncode(controlMapping.Attributes["ItemDisplayTextColumn"].Value) : string.Empty) + @"';
                            sewp_controlMappings_entry['ItemValueColumn'] = '" + (controlMapping.Attributes["ItemValueColumn"] != null ? SPEncode.ScriptEncode(controlMapping.Attributes["ItemValueColumn"].Value) : string.Empty) + @"';
                            sewp_controlMappings_entry['ExpandedWidth'] = '" + (controlMapping.Attributes["ExpandedWidth"] != null ? SPEncode.ScriptEncode(controlMapping.Attributes["ExpandedWidth"].Value) : string.Empty) + @"';
                            sewp_controlMappings_entry['DuplicateAddedAlert'] = '" + (controlMapping.Attributes["DuplicateAddedAlert"] != null ? SPEncode.ScriptEncode(controlMapping.Attributes["DuplicateAddedAlert"].Value) : string.Empty) + @"';
                        ";

                js += @"        var sewp_controlOptions = new Array();
                            ";
                foreach (XmlNode option in controlMapping.ChildNodes)
                {
                    if (option.Name.ToLower() == "option")
                    {
                        js += @"    var sewp_controlOptionsEntry = new Array();
                                    sewp_controlOptionsEntry['DisplayText'] = '" + (option.Attributes["text"] != null ? SPEncode.ScriptEncode(option.Attributes["text"].Value) : string.Empty) + @"';
                                    sewp_controlOptionsEntry['Value'] = '" + (option.Attributes["value"] != null ? SPEncode.ScriptEncode(option.Attributes["value"].Value) : string.Empty) + @"';
                                sewp_controlOptions.push(sewp_controlOptionsEntry);
                        ";
                    }
                }
                js += @"
                            sewp_controlMappings_entry['Options'] = sewp_controlOptions;
                        ";

                js += "  _sewp_controlMappings.push(sewp_controlMappings_entry);";
            }



            string searchPartID = GetSearchWebPartID();


            js += @"
var _sewp_searchPartID = ''; // client ID of search web part
var _propertiesToHaveValueSet = new Array(); // [pIndex]['ddlProperty']
var _propertiesToHaveValueSetProcessor = null;

//----------------------------------------------------------------------------
//   ON DOM READY - fires sewp_domReady the moment the DOM becomes ready
//----------------------------------------------------------------------------
var sewp_alreadyrunflag = 0;  //flag to indicate whether target function has already been run
if (document.addEventListener)
    document.addEventListener(""DOMContentLoaded"", function() { sewp_alreadyrunflag = 1; sewp_domReady() }, false);
else if (document.all && !window.opera)
{
    document.write('<script type=""text/javascript"" id=""mc_contentloadtag"" defer=""defer"" src=""javascript:void(0)""><\/script>');
    var contentloadtag = document.getElementById(""mc_contentloadtag"");
    contentloadtag.onreadystatechange = function()
    {
        if (this.readyState == ""complete"")
        {
            sewp_alreadyrunflag = 1;
            sewp_domReady();
        }
    }
}
var _mp_oldWindowOnload = window.onload;
window.onload = function()
{
    if(_mp_oldWindowOnload != null) _mp_oldWindowOnload(); // SharePoint 2010 scripts including the ribbon depends on this old method being executed
    setTimeout(""if (!sewp_alreadyrunflag) sewp_domReady()"", 0)
}


function sewp_domReady()
{
    _sewp_searchPartID = sewp_findAdvancedSearchWebPartClientID();
    sewp_registerControlMappings();
    if(typeof(sewp_securityTrimmings) != 'undefined')
        sewp_securityTrimmings();
}

function sewp_findAdvancedSearchWebPartClientID()
{
    var wpID = '';
    // Get the ClientID of the advanced search web part by finding the search button, and stripping the last part
    if(wpID.length < 1)
    {
        var cmds = document.getElementsByTagName('input');
        for(var i=0; i<cmds.length; i++)
        {
            if(cmds[i].id.indexOf('ASB_BS_SRCH_1') > -1 && cmds[i].id.indexOf('" + searchPartID + @"') > -1)
            {
                wpID = cmds[i].id.replace('_ASB_BS_SRCH_1', '');
                break;
            }
        }
    }
    return wpID;
}

function sewp_registerControlMappings()
{
    // Check that an advanced search web part ID was found
    if(_sewp_searchPartID.length < 1)
        return;
    

    // Attach an event to the Property dropdownlist so that when a mapped property is selected, display the custom input field instead
    // Dropdownlist ID's always use the same ID with an incremented index in asending order always
    var keepGoing = true;
    var pIndex = 0;
    
    while(keepGoing)
    {
        var ddlProperty = document.getElementById(_sewp_searchPartID + '_ASB_PS_plb_' + pIndex);
        if(ddlProperty != null)
        {
            var oldOnChange = ddlProperty.onchange;
            ddlProperty.setAttribute('oldOnChange', oldOnChange);
            ddlProperty.setAttribute('propertyIndex', pIndex);
            
            ddlProperty.onchange = function()
            {
                // If there are children to be removed, remove them and clear the attribute
                if(this.attributes['childrenOptionTextToRemoveOnChange'] != null && this.attributes['childrenOptionTextToRemoveOnChange'].value.length > 0)
                {
                    var childrenToRemove = this.attributes['childrenOptionTextToRemoveOnChange'].value.split(',');
                    for(var i=0; i<childrenToRemove.length; i++)
                    {
                        childrenToRemove[i] = childrenToRemove[i].replace(/^\s+|\s+$/g, ''); // trim leading & trailing space

                        // Go through each displayed property and check if it needs to be removed
                        for(var p=0; p<5; p++)
                        {
                            var ddlProperty = document.getElementById(_sewp_searchPartID + '_ASB_PS_plb_' + p);
                            
                            if(ddlProperty != null && ddlProperty.style.display != 'none' && ddlProperty.id != this.id)
                            {   
                                var selectedTextCompare = '';
                                if(typeof(ddlProperty.options[ddlProperty.selectedIndex].innerText) != 'undefined')
                                    selectedTextCompare = ddlProperty.options[ddlProperty.selectedIndex].innerText;
                                else
                                    selectedTextCompare = ddlProperty.options[ddlProperty.selectedIndex].text;

                                if(selectedTextCompare == childrenToRemove[i])
                                {   
                                    // If the remove link is visible (last property only) we can remove it, otherwise change to default value
                                    var lnkRemove = document.getElementById(_sewp_searchPartID + '_ASB_PS_lnk_remove' + p);
                                    if(lnkRemove != null && lnkRemove.style.display != 'none')
                                    {   
                                        ddlProperty.selectedIndex = 0;
                                        ddlProperty.onchange(); // makes sure the added field is hidden (FF issue only)

                                        // Remove the property
                                        if(typeof(lnkRemove.click) != 'undefined' && lnkRemove.click != null)
                                            lnkRemove.click(); // IE
                                        else // FF support
                                            eval(lnkRemove.href.replace('javascript:', ''));
                                    }
                                    else
                                    {
                                        // Set the property to default
                                        ddlProperty.selectedIndex = 0;
                                        ddlProperty.onchange();
                                    }
                                }
                            }
                        }
                    }
                    
                    this.setAttribute('childrenOptionTextToRemoveOnChange', ''); // clear child properties to be removed
                }
                
                
                var pIndex = this.attributes['propertyIndex'].value; // index of the controls for this property restriction

                // Enable equal / not equal dropdown by default
                var ddlEqual = document.getElementById(_sewp_searchPartID + '_ASB_PS_olb_' + pIndex);
                ddlEqual.disabled = false;


                var selectedText = '';
                if(typeof(this.options[this.selectedIndex].innerText) != 'undefined')
                    selectedText = this.options[this.selectedIndex].innerText;
                else
                    selectedText = this.options[this.selectedIndex].text;

                // Return to default - display the default input field and remove any added fields
                var controlContainer = document.getElementById(_sewp_searchPartID + '_ASB_PS_customFieldContainer' + pIndex);
                var txtInputField = document.getElementById(_sewp_searchPartID + '_ASB_PS_pvtb_' + pIndex); 
                var defaultSelectedValue = '';
                
                if(controlContainer != null)
                {
                    // Get the default value if it has been preserved because it wasnt used the first time around
                    if(controlContainer.attributes['defaultSelectedValue'] != null)
                        defaultSelectedValue = controlContainer.attributes['defaultSelectedValue'].value;
                    
                    controlContainer.parentNode.removeChild(controlContainer);
                    txtInputField.value = ''; // reset its value
                    txtInputField.style.display = 'inline';
                }
                else
                    defaultSelectedValue = txtInputField.value;
                
                var matchFound = false;
                for(var x=0; x<_sewp_controlMappings.length; x++)
                {
                    if(_sewp_controlMappings[x]['OptionText'] == selectedText)
                    {
                        matchFound = true;

                        // Make sure no other fields are set to this value
                        for(var p=0; p<5; p++)
                        {
                            var ddlProperty = document.getElementById(_sewp_searchPartID + '_ASB_PS_plb_' + p);
                            
                            if(ddlProperty != null && ddlProperty.style.display != 'none' && ddlProperty.id != this.id)
                            {   
                                if(ddlProperty.selectedIndex == this.selectedIndex)
                                {
                                    // set back to default and display warning
                                    if(_sewp_controlMappings[x]['DuplicateAddedAlert'] != null && _sewp_controlMappings[x]['DuplicateAddedAlert'].length > 0)
                                        alert(_sewp_controlMappings[x]['DuplicateAddedAlert']);
                                    
                                    this.selectedIndex = 0; 
                                    return;
                                }   
                            }
                        }
                        
                        // Hide input field, Append alternative field
                        if(_sewp_controlMappings[x]['ControlToUse'] == '" + PropertyRestrictionControlToUse.Dropdownlist.ToString() + @"')
                        {
                            var txtInputField = document.getElementById(_sewp_searchPartID + '_ASB_PS_pvtb_' + pIndex);

                            // Set the ID - make sure the index matches the other controls for this property
                            var ddl = document.createElement('select');
                            ddl.id = _sewp_searchPartID + '_ASB_PS_dropdownlist' + pIndex;
                            ddl.className = 'ms-advsrchPropValue';
                            //ddl.style.width = '300px';
                            ddl.setAttribute('pIndex', pIndex); // property index - combined with _sewp_searchPartID can be used to get fields
                            ddl.setAttribute('mappedFieldID', txtInputField.id);
                            ddl.setAttribute('ChildrenOptionText', _sewp_controlMappings[x]['ChildrenOptionText']);
                            ddl.setAttribute('DependentOnOptionText', _sewp_controlMappings[x]['DependentOnOptionText']);
                            ddl.setAttribute('DependentOnType', _sewp_controlMappings[x]['DependentOnType']);
                            ddl.setAttribute('defaultSelectedValue', defaultSelectedValue); // Default selected value
                            ddl.setAttribute('expandedWidth', _sewp_controlMappings[x]['ExpandedWidth']);
                            if(navigator != null && navigator.appName != null && navigator.appName.indexOf('Internet Explorer') > -1)
                            {   
                                // Change the size of the dropdownlist to display the full length of some of the items
                                ddl.onmousedown = function()
                                {
                                    if(this.attributes['expandedWidth'].value.length > 0)
                                    {
                                        this.style.position = 'absolute'; // controlContainer is relative positioned

                                        if(this.parentNode.parentNode.childNodes.length > 3)
                                            this.style.top = '-10px'; // SP2007 only position fix. Not needed in SP2010

                                        if(this.attributes['expandedWidth'].value.toLowerCase() != 'auto')
                                            this.style.width = this.attributes['expandedWidth'].value; // custom width defined in configXml
                                    }
                                    return true;
                                }
                                ddl.onblur = function()
                                {
                                    this.style.position = 'relative';
                                    this.style.top = '0px';
                                    this.style.width = ''; // default width for the class
                                }
                            }
                            ddl.onchange = function()
                            {
                                if(this.onblur)
                                    this.onblur();

                                var pIndex = this.attributes['pIndex'].value;
                                
                                // When a selection is made transfer it to the original text field so it will be treated as a property restriction
                                var selectedValue = ddl.options[ddl.selectedIndex].value;
                                var txtInputField = document.getElementById(ddl.attributes['mappedFieldID'].value);
                                if(txtInputField != null)
                                    txtInputField.value = selectedValue;
                                
                                // Check for dependency - if one exists attempt to add another property and display it
                                var childrenOptionText = this.attributes['ChildrenOptionText'].value;
                                if(childrenOptionText.length > 0)
                                {
                                    // Make the ddlProperty aware of the children that have been added. Next time it is changed they will
                                    // also be removed / set to back to something else
                                    var ddlProperty = document.getElementById(_sewp_searchPartID + '_ASB_PS_plb_' + pIndex)
                                    ddlProperty.setAttribute('childrenOptionTextToRemoveOnChange', childrenOptionText);

                                    var childrenOptions = childrenOptionText.split(',');
                                    if(childrenOptions.length > 0)
                                    {
                                        for(var i=0; i<childrenOptions.length; i++)
                                        {
                                            childrenOptions[i] = childrenOptions[i].replace(/^\s+|\s+$/g, ''); // trim leading & trailing space
                                            
                                            
                                            // Check that the property isn't already added
                                            var isAlreadyAdded = false;
                                            
                                            var ddlProperty = null;
                                            isAlreadyAddedChecker:
                                            for(var p=0; p<5; p++)
                                            {
                                                var ddlPropertyCheck = document.getElementById(_sewp_searchPartID + '_ASB_PS_plb_' + p);
                                                
                                                var ddlPropertySelectedText = '';
                                                if(typeof(ddlPropertyCheck.options[ddlPropertyCheck.selectedIndex].innerText) != 'undefined')
                                                    ddlPropertySelectedText = ddlPropertyCheck.options[ddlPropertyCheck.selectedIndex].innerText;
                                                else
                                                    ddlPropertySelectedText = ddlPropertyCheck.options[ddlPropertyCheck.selectedIndex].text;

                                                if(ddlPropertyCheck != null && ddlPropertyCheck.style.display != 'none' && ddlPropertySelectedText == childrenOptions[i])
                                                {
                                                    // Already added, don't add it again
                                                    isAlreadyAdded = true;
                                                    ddlProperty = ddlPropertyCheck; // keep reference to it
                                                    
                                                    break isAlreadyAddedChecker;
                                                }
                                            }
                                            
                                            
                                            if(!isAlreadyAdded)
                                            {
                                                // Add / find an unused property and then populate its dropdown using the value of this item 
                                                // (the parent) as a parameter
                                                
                                                // first check if there is a property which hasn't been set
                                                checkUnsetProperty:
                                                for(var p=0; p<5; p++)
                                                {
                                                    var ddlPropertyUnselected = document.getElementById(_sewp_searchPartID + '_ASB_PS_plb_' + p);
                                                    if(ddlPropertyUnselected.style.display != 'none' && ddlPropertyUnselected.selectedIndex == 0)
                                                    {
                                                        ddlProperty = ddlPropertyUnselected;
                                                        break checkUnsetProperty;
                                                    }
                                                }
                                                
                                                if(ddlProperty == null)
                                                {
                                                    // Needs to be added using the only visible 'Add property' link (not a hidden link)
                                                    var pIndexOfAdded = -1;
                                                    propertyAdder:
                                                    for(var p=4; p>-1; p--)
                                                    {
                                                        var addPropertyLink = document.getElementById(_sewp_searchPartID + '_ASB_PS_lnk_' + p);
                                                        if(addPropertyLink != null && addPropertyLink.style.display != 'none')
                                                        {   
                                                            // Add the next property restriction
                                                            if(typeof(addPropertyLink.click) != 'undefined' && addPropertyLink.click != null)
                                                                addPropertyLink.click(); // IE
                                                            else // FF support
                                                                eval(addPropertyLink.href.replace('javascript:', ''));
                                                            
                                                            pIndexOfAdded = p+1;
                                                            break propertyAdder;
                                                        }
                                                    }
                                                    
                                                    
                                                    // Get the reference of the last field added
                                                    // (sharepoint search web part supports maximum 5 properties added, so start at index 4)
                                                    ddlProperty = document.getElementById(_sewp_searchPartID + '_ASB_PS_plb_' + pIndexOfAdded);
                                                    
                                                }
                                            }
                                            
                                            // Interval is needed for IE6 support - events are not processed immediately before continuing
                                            // So the value on the new property can only be selected when the event has processed and it has been added
                                            var propertiesToHaveValueSet = new Array();
                                            propertiesToHaveValueSet['ddlProperty'] = ddlProperty;
                                            propertiesToHaveValueSet['value'] = childrenOptions[i];
                                            _propertiesToHaveValueSet.push(propertiesToHaveValueSet);


                                            // Get a reference to ddlproperty and set its value
                                            if(_propertiesToHaveValueSetProcessor == null || _propertiesToHaveValueSetProcessor == -1)
                                            {
                                                _propertiesToHaveValueSetProcessor = setInterval(function()
                                                {
                                                    for(var i=0; i<_propertiesToHaveValueSet.length; i++)
                                                    {
                                                        if(_propertiesToHaveValueSet[i] != null)
                                                        {
                                                            var ddlProperty = _propertiesToHaveValueSet[i]['ddlProperty'];
                                                            
                                                            if(ddlProperty != null && ddlProperty.style.display != 'none')
                                                            {    
                                                                selectedDependentValueSearcher:
                                                                for(var x=0; x<ddlProperty.options.length; x++)
                                                                {
                                                                    if(ddlProperty.options[x].text == _propertiesToHaveValueSet[i]['value'])
                                                                    {
                                                                        ddlProperty.selectedIndex = x;
                                                                        ddlProperty.onchange();
                                                                        
                                                                        break selectedDependentValueSearcher;
                                                                    }
                                                                }
                                                                
                                                                // Remove entry i from the queue
                                                                _propertiesToHaveValueSet.splice(i,1);
                                                            }
                                                        }
                                                    }
                                                    if(_propertiesToHaveValueSet.length < 1)
                                                    {   
                                                        clearInterval(_propertiesToHaveValueSetProcessor);
                                                        _propertiesToHaveValueSetProcessor = -1;
                                                    }
                                                }, 2);
                                            }
                                            
                                            
                                        }
                                    }
                                }
                            }
                            
                            // ControlContainer - is necessary to remove custom fields again when switching back to default text input field
                            var ddlAndOr = document.getElementById(_sewp_searchPartID + '_ASB_PS_lolb_' + pIndex);
                            var controlContainer = document.createElement('span');
                            controlContainer.id = _sewp_searchPartID + '_ASB_PS_customFieldContainer' + pIndex;
                            controlContainer.style.position = 'relative';
                            controlContainer.appendChild(ddl); 
                            
                            // Hide default input field, append ddl
                            txtInputField.style.display = 'none'; //TESTING

                            if(txtInputField.parentNode.childNodes.length > 3) // In SP2010 all controls are in one TD
                                txtInputField.parentNode.insertBefore(controlContainer, ddlAndOr); // SP2010 - needs to use insertBefore
                            else // in SP2007 each control is in a separate TD
                                txtInputField.parentNode.appendChild(controlContainer); // SP2007 - needs to use AppendChild
                            
                            // Disable not equal option
//                            var ddlEqual = document.getElementById(_sewp_searchPartID + '_ASB_PS_olb_' + pIndex);
//                            ddlEqual.selectedIndex = 0;
//                            ddlEqual.disabled = true; //TESTING
                            
                            
                            //var customEqualContainer = document.createElement('span');
                            //customEqualContainer.id = _sewp_searchPartID + '_ASB_PS_customEqualContainer' + pIndex;
                            
                            
                            // Remove link - make sure it also hides the added custom field
                            var lnkRemove = document.getElementById(_sewp_searchPartID + '_ASB_PS_lnk_remove' + pIndex);
                            if(lnkRemove != null) // the first column can't be removed - no link
                            {
                                lnkRemove.setAttribute('controlContainerID', controlContainer.id);
                                lnkRemove.onclick = function()
                                {
                                    var controlContainer = document.getElementById(this.attributes['controlContainerID'].value);
                                    if(controlContainer != null)
                                        controlContainer.style.display='none';
                                    
                                    //var oldOnClick = lnkRemove.onclick;
                                    //lnkRemove.setAttribute('oldOnClick', oldOnClick);
                                }
                            }
                            
                            
                            
                            // Populate the dropdownlist asynchronously 
                            // - if this is dependent on another property value then get that value and pass it along in the callback
                            var dependentOnOptionText = ddl.attributes['DependentOnOptionText'].value;
                            var strDependentOnValue = '';
                            // Find the value of the dependent option
                            // (sharepoint search web part supports maximum 5 properties added, so end at index 4)
                            var bParentControlFound = false;
                            dependentValueSearcher:
                            for(var p=0; p<5; p++)
                            {
                                var ddlProperty = document.getElementById(_sewp_searchPartID + '_ASB_PS_plb_' + p);
                                
                                if(ddlProperty != null && ddlProperty.style.display != 'none' 
                                    && ddlProperty.options[ddlProperty.selectedIndex].value == dependentOnOptionText)
                                {   
                                    bParentControlFound = true;
                                    var ddlPropertyValue = document.getElementById(_sewp_searchPartID + '_ASB_PS_dropdownlist' + p);
                                    if(ddlPropertyValue != null) // if we are using dropdowns, get the ID of the selected option
                                    {
                                        // After a search is performed onchange is called to restore values.
                                        // - make sure the child property doesn't try to load before its dependency has loaded from callback
                                        try
                                        {
                                            strDependentOnValue = ddlPropertyValue.options[ddlPropertyValue.selectedIndex].attributes['itemID'].value;
                                            break dependentValueSearcher;
                                        }
                                        catch(e)
                                        {
                                            // Keep default value, because it was not used the first time
                                            var controlContainer = document.getElementById(_sewp_searchPartID + '_ASB_PS_customFieldContainer' + pIndex);
                                            var ddlPropertyValue = document.getElementById(_sewp_searchPartID + '_ASB_PS_dropdownlist' + pIndex);
                                            controlContainer.setAttribute('defaultSelectedValue', ddlPropertyValue.attributes['defaultSelectedValue'].value);
                                            
                                            return; // Don't continue callback without knowing the value of the property this is dependent on
                                        }
                                    }
                                    else // default to the standard text field, and get its text value
                                    {
                                        var txtProperty = document.getElementById(_sewp_searchPartID + '_ASB_PS_pvtb_' + p);
                                        strDependentOnValue = txtProperty.value;
                                        break dependentValueSearcher;
                                    }
                                }   
                            }
                            if(dependentOnOptionText.length > 0 && !bParentControlFound)
                            {
                                // Dependent on value couldn't be found. Could be because the parent control hasnt been selected yet
                                // therefore set this dropdown to the parent control
                                for(var p=0; p<this.options.length; p++)
                                {
                                    if(this.options[p].value == dependentOnOptionText)
                                    {
                                        this.selectedIndex = p;
                                        this.onchange();
                                        return;
                                    }
                                }
                            }
                            
                            // Default selected value
                            var defaultSelectedValue = ddl.attributes['defaultSelectedValue'].value;
                            this.setAttribute('defaultSelectedValue', ''); // remove default selected value after the first time it is used

                            var strDependentOnType = '';
                            if(ddl.attributes['DependentOnType'] != null)
                                strDependentOnType = ddl.attributes['DependentOnType'].value;
                            
                            
                            // Populate ddl with hard coded options
                            if(_sewp_controlMappings[x]['Options'] != null && _sewp_controlMappings[x]['Options'].length > 0)
                            {
                                sewp_setDropdownListColumns(ddl.id, _sewp_controlMappings[x]['Options'], defaultSelectedValue);
//                                controlContainer.setAttribute('defaultSelectedValue', ''); // clear this property, this isnt a callback
                            }
                            // Populate ddl from server callback (from a SPList)
                            if(_sewp_controlMappings[x]['SourceList'] != null && _sewp_controlMappings[x]['SourceList'].length > 0)
                                sewp_CallServer('GetItemsFromList,' + ddl.id + ',' + _sewp_controlMappings[x]['SourceList'] + ',' + _sewp_controlMappings[x]['SourceListParentWeb'] + ',' + _sewp_controlMappings[x]['ItemDisplayTextColumn'] + ',' + _sewp_controlMappings[x]['ItemValueColumn'] + ',' + strDependentOnValue + ',' + strDependentOnType + ',' + defaultSelectedValue);
                        }
                        
                        break;
                    }
                }
                if(!matchFound)
                {
//                    if(confirm('debug?')) debugger;
                    // No match was found to use a custom control for this option, therefore use the default

                    // Run the previous onchange event - this has implications for other data types like booleans, numbers, dates
                    var oldOnChange = this.attributes['oldOnChange'].value;
                    oldOnChange = oldOnChange.substring(oldOnChange.indexOf('ChangeOperatorDDL'), oldOnChange.indexOf('}', oldOnChange.indexOf('ChangeOperatorDDL')));
                    eval(oldOnChange);
                }
            }
            
            ddlProperty.onchange();
            
            pIndex++;
        }
        else
            break;
        
        
    }
}

function sewp_setDropdownListColumns(ddlID, optionsArray, selectedValue)
{
    var ddl = document.getElementById(ddlID);
    //if(ddl == null) return; //TESTING

    var expandedWidth = parseFloat('0');
    var characterWidth = parseFloat('5.11'); // ASSUMED LENGTH OF 1 CHARACTER
    var widthPadding = parseFloat('18'); // Additional trailing padding
    for(var i=0; i<optionsArray.length; i++)
    {
        var opt = document.createElement('OPTION');
        opt.text = optionsArray[i]['DisplayText'];
        opt.value = optionsArray[i]['Value'];
        if(typeof(optionsArray[i]['itemID']) != 'undefined' && optionsArray[i]['itemID'] != null)
            opt.setAttribute('itemID', optionsArray[i]['itemID']);
        ddl.options.add(opt);

        if(optionsArray[i]['isSelected'] == 'true')
            ddl.selectedIndex = i;
        if(optionsArray[i]['Value'] == selectedValue)
            ddl.selectedIndex = i;
        
        if(parseFloat(characterWidth) * parseFloat(optionsArray[i]['DisplayText'].length) > parseFloat(expandedWidth))
            expandedWidth = parseFloat(characterWidth) * parseFloat(optionsArray[i]['DisplayText'].length) + widthPadding;
    }
    
    if(ddl.attributes['expandedWidth'].value.toLowerCase() == 'auto')
        ddl.setAttribute('expandedWidth', '' + expandedWidth);
    
    if(typeof(ddl.onchange) != 'undefined' && ddl.onchange != null)
        ddl.onchange();
}
";


            // Security trimmed properties in advanced search web part
            js += @"
function sewp_securityTrimmings(){
";
            XmlNode securityTrimmings = xmlConfig.SelectSingleNode("/Configuration/SecurityTrimmings");
            if (securityTrimmings != null)
            {
                foreach (XmlNode securityTrim in securityTrimmings)
                {
                    // Check if current user should have access
                    string[] groups = null;
                    if (securityTrim.Attributes["Groups"] != null)
                        groups = securityTrim.Attributes["Groups"].Value.Split(',');

                    string webUrl = string.Empty;
                    if (securityTrim.Attributes["TeamSiteUrl"] != null)
                        webUrl = securityTrim.Attributes["TeamSiteUrl"].Value;

                    SPWeb web = null;
                    if (!string.IsNullOrEmpty(webUrl))
                    {
                        // Can be a site relative web URL or full web URL
                        if (!webUrl.Contains("http://"))
                        {
                            if (webUrl.IndexOf("/") == 0)
                                webUrl = webUrl.Substring(1);
                            webUrl = SPContext.Current.Site.Url + "/" + webUrl;
                        }

                        using (SPSite site = new SPSite(webUrl))
                        {
                            web = site.OpenWeb();
                        }
                    }
                    else
                        web = SPContext.Current.Site.RootWeb;

                    bool hasAccess = false;
                    if (groups != null && groups.Length > 0)
                    {
                        foreach (string groupName in groups)
                        {
                            try
                            {
                                if (web.Groups[groupName].ContainsCurrentUser)
                                    hasAccess = true;
                            }
                            catch { } // group not found
                        }
                    }
                    else
                        hasAccess = true; // No groups specified, assume there is no restriction

                    web.Dispose();

                    if (!hasAccess)
                    {
                        js += @"
                            sewp_hidePropertyRestrictionOption('" + SPEncode.ScriptEncode(securityTrim.Attributes["OptionText"].Value) + @"');";
                        ;
                    }
                }

                js += @"
} // end of function 'sewp_securityTrimmings'

function sewp_hidePropertyRestrictionOption(optionText)
{
    for(var p=0; p<5; p++)
    {
        var ddlProperty = document.getElementById(_sewp_searchPartID + '_ASB_PS_plb_' + p);
        if(ddlProperty==null) 
            continue;
        
        // remove option by option text
        for(var i=0; i<ddlProperty.options.length; i++)
        {
            var selectedText = '';
            if(typeof(ddlProperty.options[i].innerText) != 'undefined')
                selectedText = ddlProperty.options[i].innerText; // IE
            else
                selectedText = ddlProperty.options[i].text; // FF
            
            if(selectedText == optionText)
            {
                ddlProperty.remove(i);
                return;
            }
        }
    }
}
";
            }








            if (Page != null)
                Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "jsScripts" + this.ClientID, js, true);
        }

        public string GetSearchWebPartID()
        {
            using (SPWeb web = SPContext.Current.Web)
            {
                SPLimitedWebPartManager wpManager = web.GetLimitedWebPartManager(Page.Request.Url.AbsoluteUri, PersonalizationScope.Shared);
                //SPLimitedWebPartManager wpManager = web.GetLimitedWebPartManager("WebPageURL", PersonalizationScope.Shared);
                SPLimitedWebPartCollection webparts = wpManager.WebParts;

                foreach (Microsoft.SharePoint.WebPartPages.WebPart wp in webparts)
                {
                    if (wp.GetType().Name.ToString().Contains("AdvancedSearchBox"))
                    {
                        return wp.ClientID;
                    }
                }
            }

            return string.Empty;
        }

        public override EditorPartCollection CreateEditorParts()
        {
            ArrayList editorArray = new ArrayList();
            SearchExtensionEditorPart edPart = new SearchExtensionEditorPart();
            edPart.ID = this.ID + "_editorPart1";
            edPart.Title = "Search Extension Configuration";
            edPart.ChromeState = PartChromeState.Normal;
            editorArray.Add(edPart);

            EditorPartCollection editorParts = new EditorPartCollection(editorArray);
            return editorParts;
        }

        private void HandleException(Exception ex)
        {
            this.Controls.Clear();
            this.Controls.Add(new LiteralControl(ex.Message));
        }


        #region ICallbackEventHandler functions
        private string jsReturnValue = string.Empty;
        public void RaiseCallbackEvent(string eventArgument)
        {
            jsReturnValue = string.Empty;

            string[] args = eventArgument.Split(',');

            if (args.Length > 0)
            {
                // Populate dropdownlist with items from a sharepoint list
                if (args[0] == "GetItemsFromList")
                {
                    string ddlID = args[1];
                    string sourceList = args[2];
                    string sourceListParentWeb = args[3];
                    string itemDisplayTextColumn = args[4];
                    string itemValueColumn = args[5];
                    string strDependentOnValue = args[6];
                    string strDependentOnType = args[7];
                    string defaultSelectedValue = args[8];

                    int folderID = -1;
                    if (strDependentOnType == PropertyRestrictionDependentOnType.ParentFolder.ToString())
                    {
                        if (strDependentOnValue.Length < 1)
                            return;
                        else
                            folderID = Convert.ToInt32(strDependentOnValue);
                    }

                    StringBuilder sb = new StringBuilder();

                    try
                    {
                        using (SPWeb web = SPContext.Current.Site.AllWebs[sourceListParentWeb])
                        {
                            SPList list = web.Lists[sourceList];
                            SPListItemCollection items = null;

                            if (folderID > -1)
                            {
                                SPFolder folder = list.GetItemById(folderID).Folder;

                                SPQuery query = new SPQuery();
                                query.Query = "<Query><OrderBy><FieldRef Name='Title' Ascending='True' /></OrderBy></Query>"; // All items at root
                                query.Folder = folder;
                                items = list.GetItems(query);
                            }
                            else
                            {
                                // By default a query will retrieve items at the root level unless ViewAttributes is set to "Scope='Recursive'"
                                SPQuery query = new SPQuery();
                                query.Query = "<Query><OrderBy><FieldRef Name='Title' Ascending='True' /></OrderBy></Query>"; // All items at root
                                items = list.GetItems(query);
                            }

                            if (items != null)
                            {
                                sb.Append("var _ddlColumnsArray = new Array();");
                                foreach (SPListItem item in items)
                                {
                                    string strDisplayText = item[itemDisplayTextColumn].ToString();
                                    string strValue = item[itemValueColumn].ToString();
                                    string strItemID = item.ID.ToString();
                                    bool isSelected = (defaultSelectedValue == strDisplayText);
                                    sb.AppendLine("var ddlColumnsArrayEntry = new Array();");
                                    sb.AppendLine("ddlColumnsArrayEntry['DisplayText'] = '" + SPEncode.ScriptEncode(strDisplayText) + "';");
                                    sb.AppendLine("ddlColumnsArrayEntry['Value'] = '" + SPEncode.ScriptEncode(strValue) + "';");
                                    sb.AppendLine("ddlColumnsArrayEntry['itemID'] = '" + SPEncode.ScriptEncode(strItemID) + "';");
                                    sb.AppendLine("ddlColumnsArrayEntry['isSelected'] = '" + SPEncode.ScriptEncode(isSelected.ToString().ToLower()) + "';");
                                    sb.AppendLine("_ddlColumnsArray.push(ddlColumnsArrayEntry);");
                                }
                                sb.AppendLine("sewp_setDropdownListColumns('" + ddlID + "', _ddlColumnsArray);");
                                jsReturnValue = sb.ToString();
                            }
                        }
                    }
                    catch { }

                }
            }
        }

        public string GetCallbackResult()
        {
            return jsReturnValue;
        }
        #endregion



    }
}
